﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Net;

namespace WebDav
{
    public class WebDav
    {
        private String _username = null;
        private String _password =  null;


        public struct Entity
        {
            public String Url;
            public String FileName;
            public bool IsDirectory;
        }

        public WebDav(String username, String password)
        {
            _username = username;
            _password = password;
        }

        private void ReadWriteStream(Stream readStream, Stream writeStream)
        {
            int Length = 256;
            Byte[] buffer = new Byte[Length];
            int bytesRead = readStream.Read(buffer, 0, Length);
            // write the required bytes
            while (bytesRead > 0)
            {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = readStream.Read(buffer, 0, Length);
            }
            //readStream.Close();
            writeStream.Close();
        }

        public bool Download(Entity entity, String localPath)
        {
            WebClient client = new WebClient();
            // Download md5 file
            try
            {
                String[] tab = entity.FileName.Split('/');
                String file = tab[tab.Length - 1];

                client.DownloadFile(entity.Url + "/" + entity.FileName, Path.Combine(localPath, file));

                return true;
            }
            catch (Exception e)
            {
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public List<Entity> BrowseDirectory(string url)
        {
            Stream RequestStream;
            Stream ResponseStream;
            XmlDocument xmlDoc = null;
            List<Entity> ret = new List<Entity>();
            HttpWebResponse webResp;

            string strBody = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><d:propfind xmlns:d='DAV:'><d:prop><d:displayname/><d:getcontentlength /><d:creationdate /><d:getlastmodified /><d:ishidden /><d:iscollection /><d:getcontentlength /><d:creationdate /><d:getlastmodified /><d:ishidden /><d:iscollection /></d:prop></d:propfind>";

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "PROPFIND";
            req.Headers.Add("Depth: 1");

            // Authentification
            if (!String.IsNullOrEmpty(_username))
            {
                NetworkCredential networkCredential = new NetworkCredential(_username, _password);
                req.Credentials = networkCredential;
            }

            byte[] bytes = Encoding.UTF8.GetBytes((string)strBody);

            req.ContentType = "text/xml";
            req.ContentLength = bytes.LongLength;

            RequestStream = req.GetRequestStream();
            RequestStream.Write(bytes, 0, bytes.Length);
            RequestStream.Close();

            try
            {
                webResp = (HttpWebResponse)req.GetResponse();
                ResponseStream = webResp.GetResponseStream();
            }
            catch
            {
                return null;
            }

            xmlDoc = new XmlDocument();
            xmlDoc.Load(ResponseStream);


            XmlNamespaceManager manager = new XmlNamespaceManager(xmlDoc.NameTable);
            manager.AddNamespace("a", "DAV:");

            XmlNodeList Confs = xmlDoc.SelectNodes("/a:multistatus/a:response", manager);

            foreach (XmlNode Conf in Confs)
            {
                try
                {
                    String defhref = Conf.SelectSingleNode("a:href", manager).InnerText;
                    Entity ent = new Entity();

                    Uri uri = new Uri(url);
                    

                    ent.Url = "http://" + uri.Host + "/";
                    ent.FileName = defhref;
                    if (defhref.Substring(defhref.Length - 1, 1) == "/")
                        ent.IsDirectory = true;
                    else
                        ent.IsDirectory = false;

                    ret.Add(ent);
                }
                catch (Exception e)
                {

                }
            }

            ResponseStream.Close();
            webResp.Close();

            return ret;
        }

        public bool CreateDirectory(String url, ref HttpStatusCode statusCode)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            bool status;
            req.Method = "MKCOL";

            if (!String.IsNullOrEmpty(_username))
            {
                NetworkCredential networkCredential = new NetworkCredential(_username, _password);
                req.Credentials = networkCredential;
            }

            HttpWebResponse webResp = (HttpWebResponse)req.GetResponse();
            statusCode = webResp.StatusCode;

            if (webResp.StatusCode == HttpStatusCode.Created)
                status = true;
            else
                status = false;

            webResp.Close();
            return status;
        }

        public bool Delete(String url, ref HttpStatusCode statusCode)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            HttpWebResponse webResp;
            bool status;
            req.Method = "DELETE";

            if (!String.IsNullOrEmpty(_username))
            {
                NetworkCredential networkCredential = new NetworkCredential(_username, _password);
                req.Credentials = networkCredential;
            }

            try
            {
                webResp = (HttpWebResponse)req.GetResponse();
                statusCode = webResp.StatusCode;
                if (webResp.StatusCode == HttpStatusCode.Found)
                    status = true;
                else
                    status = false;
            } catch (Exception e)
            {
                statusCode = HttpStatusCode.BadRequest;
                return false;
            }


            webResp.Close();
            return status;
        }

        private Byte[] getFileBytes(string fileName)
        {
            //Stream stream = new FileStream(fileName, FileMode.Open,FileAccess.Read);
            StreamReader stream = new StreamReader(fileName);

            BinaryReader binReader = new BinaryReader(stream.BaseStream);
            Byte[] result = binReader.ReadBytes((Int32)stream.BaseStream.Length);
            stream.Close();

            return result;
        }

        public bool UploadFile(String url, String localFileName, ref HttpStatusCode statusCode)
        {
            string bSuccess;
            HttpStatusCode iStatus;
            string sStatus;
            string sResponse;
            bool status;

            Byte[] Data = getFileBytes(localFileName);

            string FileNameUrl;
            FileNameUrl = url + "/" + Path.GetFileName(localFileName);

            HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
            req.Method = "PUT";
            req.ContentLength = Data.LongLength;

            if (!String.IsNullOrEmpty(_username))
            {
                NetworkCredential networkCredential = new NetworkCredential(_username, _password);
                req.Credentials = networkCredential;
            }

            Stream stream = req.GetRequestStream();
            stream.Write(Data, 0, Data.Length);
            stream.Close();
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)req.GetResponse();
            }
            catch
            {
                return false;
            }

            iStatus = response.StatusCode;
            sStatus = response.StatusDescription;
            
            if (iStatus == HttpStatusCode.OK || iStatus == HttpStatusCode.Created)
                status = true;
            else if (iStatus == HttpStatusCode.Unauthorized)
                status = false;
            else
                status = false;

            response.Close();

            statusCode = iStatus;
            return status;
        }
    }
}
